<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>OpenLayers - 栅格数据投影</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/components/prism-core.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/autoloader/prism-autoloader.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/toolbar/prism-toolbar.min.js"></script>
  <script
    src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
  <link rel="stylesheet" type="text/css"
    href="https://fonts.googleapis.com/css?family=Quattrocento+Sans:400,400italic,700" crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css"
    crossorigin="anonymous">
  <link rel="stylesheet" type="text/css"
    href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/fontawesome.min.css"
    crossorigin="anonymous">
  <link rel="stylesheet" type="text/css"
    href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/solid.css" crossorigin="anonymous">
  <link rel="stylesheet" type="text/css"
    href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/brands.css" crossorigin="anonymous">
  <link rel="stylesheet" type="text/css" href="/theme/ol.css">
  <link rel="stylesheet" type="text/css" href="/theme/site.css">
  <link rel="icon" type="image/svg+xml" href="/theme/img/logo-light.svg" media="(prefers-color-scheme: light)" />
  <link rel="icon" type="image/svg+xml" href="/theme/img/logo-dark.svg" media="(prefers-color-scheme: dark)" />
</head>

<body>
  <header class="navbar navbar-expand-md navbar-dark mb-3 px-3 py-0 fixed-top" role="navigation">
    <a class="navbar-brand" href="/"><img src="/theme/img/logo-dark.svg" width="70" height="70"
        alt="">&nbsp;OpenLayers</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#olmenu"
      aria-controls="olmenu" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <!-- menu items that get hidden below 768px width -->
    <nav class="collapse navbar-collapse" id="olmenu">
      <ul class="nav navbar-nav ms-auto">
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" id="docdropdown" role="button" data-bs-toggle="dropdown"
            aria-haspopup="true" aria-expanded="false">Docs</a>
          <div class="dropdown-menu dropdown-menu-end mb-3" aria-labelledby="docdropdown">
            <a class="dropdown-item" href="/doc/">Docs</a>
            <div class="dropdown-divider"></div>
            <a class="dropdown-item" href="/doc/quickstart.html"><i class="fa fa-check fa-fw me-2 fa-lg"></i>快速入门</a>
            <a class="dropdown-item" href="/doc/faq.html"><i class="fa fa-question fa-fw me-2 fa-lg"></i>常见问题</a>
            <a class="dropdown-item" href="/doc/tutorials/"><i class="fa fa-book fa-fw me-2 fa-lg"></i>教程</a>

          </div>
        </li>
        <li class="nav-item"><a class="nav-link" href="/en/latest/examples/">Examples</a></li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" id="apidropdown" role="button" data-bs-toggle="dropdown"
            aria-haspopup="true" aria-expanded="false">
            <i class="fa fa-sitemap me-1"></i>API
          </a>
          <div class="dropdown-menu dropdown-menu-end mb-3" aria-labelledby="apidropdown">
            <a class="dropdown-item" href="/en/latest/apidoc/"><i class="fa fa-sitemap fa-fw me-2 fa-lg"></i>v8.2.0
              (latest)</a </div>
        </li>
      </ul>
    </nav>
  </header>

  <div class="container">
    <h1 id="raster-reprojection"> 栅格数据投影</h1>
    <p>
      OpenLayers能够在与服务器提供的坐标系不同的坐标系中显示来自WMS、WMTS、静态图像和许多其他来源的光栅数据。图像的地图投影的转换直接发生在网络浏览器中。任何Proj4js支持的坐标参考系统中的视图都是可能的，以前不兼容的层现在可以组合和覆盖。
    </p>
    <h1 id="usage">用法</h1>
    <p>API 的使用非常简单。只需在<code>ol/View</code>上指定正确的投影 (例如使用 <a href="https://epsg.io">EPSG</a> 代码)
      :</p>
    <pre><code class="language-js">import Map from &#39;ol/Map.js&#39;;
import TileLayer from &#39;ol/layer/Tile.js&#39;;
import TileWMS from &#39;ol/source/TileWMS.js&#39;;
import View from &#39;ol/View.js&#39;;

const map = new Map({
  target: &#39;map&#39;,
  view: new View({
    projection: &#39;EPSG:3857&#39;, // here is the view projection
    center: [0, 0],
    zoom: 2,
  }),
  layers: [
    new TileLayer({
      source: new TileWMS({
        projection: &#39;EPSG:4326&#39;, // here is the source projection
        url: &#39;https://ahocevar.com/geoserver/wms&#39;,
        params: {
          &#39;LAYERS&#39;: &#39;ne:NE1_HR_LC_SR_W_DR&#39;,
        },
      }),
    }),
  ],
});
</code></pre>
    <p>如果源(基于 <code>ol/source/TileImage</code> 或者 <code>ol/source/Image</code>) 的投影与
      与当前 <code>ol/View</code>的投影不同，则在后台自动进行重投影。</p>
    <h3 id="examples">示例</h3>
    <ul>
      <li><a href="/en/latest/examples/reprojection.html">光栅投影演示</a></li>
      <li><a href="/en/latest/examples/reprojection-wgs84.html">基于WGS84投影</a></li>
      <li><a href="/en/latest/examples/reprojection-by-code.html">使用EPSG.io数据库搜索进行投影</a></li>
      <li><a href="/en/latest/examples/reprojection-image.html">图像投影</a></li>
    </ul>
    <h3 id="custom-projection">自定义投影</h3>
    <p>使用自定义投影的最简单方法是向您的项目添加 <a href="http://proj4js.org/">Proj4js</a>库，然后使用Proj4js字符串定义投影。可以通过以下命令进行安装：</p>
    <pre><code>npm install proj4
</code></pre>
    <p>以下示例展示了<a href="https://epsg.io/27700">英国国家网格</a>的定义：</p>
    <pre><code class="language-js">import proj4 from &#39;proj4&#39;;
import {get as getProjection} from &#39;ol/proj.js&#39;;
import {register} from &#39;ol/proj/proj4.js&#39;;

proj4.defs(&#39;EPSG:27700&#39;, &#39;+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 &#39; +
    &#39;+x_0=400000 +y_0=-100000 +ellps=airy &#39; +
    &#39;+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 &#39; +
    &#39;+units=m +no_defs&#39;);
register(proj4);
const proj27700 = getProjection(&#39;EPSG:27700&#39;);
proj27700.setExtent([0, 0, 700000, 1300000]);
</code></pre>
    <h3 id="change-of-the-view-projection">视图投影的更改</h3>
    <p>要切换用于显示地图的投影，您必须在<code>ol/Map</code> 上设置一个具有选定投影的新<code>ol/View</code>:</p>
    <pre><code class="language-js">map.setView(new View({
  projection: &#39;EPSG:27700&#39;,
  center: [400000, 650000],
  zoom: 4,
}));
</code></pre>
    <h2 id="tilegrid-and-extents">瓦片网格和范围</h2>(TileGrid and Extents)
    <p>当需要重新投影时，会从原始源瓦片创建新的瓦片(在目标投影中)
      。默认情况下，重新投影的瓦片的瓦片网格是使用<code>ol/tilegrid~getForProjection(projection)</code>内部构建的。为了正常工作，投影应该有定义的范围（见上文）。
    </p>
    <p>
      另外，可以通过手动构建自定义目标瓦片网格，并将其设置在源实例上，使用<code>ol/tilegrid~getForProjection(projection)</code>。当将投影重新投影到指定的投影时，将使用此瓦片网格而不是创建默认的瓦片网格。
      在某些情况下，这可以用于优化性能（通过调整瓦片大小）或视觉质量（通过指定分辨率）。
    </p>
    <h1 id="how-it-works">工作原理</h1>
    <p>重新投影过程基于三角形 – 目标栅格被划分为有限数量的三角形,使用<code>ol/proj</code> 功能 (通常使用<a href="http://proj4js.org/">proj4js</a>
      自定义转换)对顶点进行变换。 三角形内的像素重新投影通过仿射变换进行近似处理 (由canvas 2d上下文提供硬件加速渲染):</p>
    <img src="raster-reprojection-resources/how-it-works.jpg" alt="How it works" width="600" />

    <p>通过这种方式，我们可以在几乎任何硬件（具有canvas 2d支持）上支持proj4js（甚至自定义转换函数）的广泛投影，并且只需要相对较少的实际转换计算。
    </p>
    <p>重新投影的精度由三角形的数量限制。</p>
    <p>重新投影过程保留从源（png或gif）提供的栅格数据的透明度，并且由重新投影生成的间隙和无数据像素自动透明。</p>
    <h3 id="dynamic-triangulation">动态三角形化</h3>
    <p>上图显示了当使用有限数量的三角形进行转换时（右图，EPSG：3857），原始图像（左图，EPSG：27700）的明显错误（特别是在边缘上）。通过增加使用的三角形数量，可以将错误最小化。</p>
    <p>由于某些转换需要更详细的三角形网络，因此动态三角形化过程会自动测量重新投影误差，并通过迭代细分来满足特定的误差阈值：/p>
      <img src="raster-reprojection-resources/iterative-triangulation.png" alt="Iterative triangulation" width="600" />

    <p>对于调试，可以通过<code>ol.source.TileImage#setRenderReprojectionEdges(true)</code>启用重新投影边缘的渲染。
    </p>
    <h1 id="advanced">高级</h1>
    <h3 id="triangulation-precision-threshold">三角形化精度阈值</h3>
    <p>默认的<a href="#dynamic-triangulation">像素三角形化误差</a> 阈值为
      <code>ERROR_THRESHOLD</code> (0.5像素)。在需要为不同源定义不同阈值的情况下，可以在构造瓦片图像源时传递<code>reprojectionErrorThreshold</code> 选项。
    </p>
    <h3 id="limiting-visibility-of-reprojected-map-by-extent">通过范围限制重新投影地图的可见性</h3>
    <p>重新投影算法使用逆变换 (从 <em>视图投影</em> 到 <em>数据投影</em>)。 对于某些坐标系统，这可能导致地图上源数据的“双重出现”。
      例如，当将瑞士地图从EPSG：21781重新投影到EPSG：3857时，它显示了两次：一次在欧洲的适当位置，另一次在新西兰附近的太平洋上，在地球的另一侧。</p>
    <img src="raster-reprojection-resources/double-occurrence.jpg" alt="Double occurrence of a reprojected map"
      width="600" />

    <p>尽管这种逆变换是数学上正确的行为，但用户不会期望图层在多个地方可见。一种可能的通用解决方案是计算每个顶点的正向变换 - 但这将显著降低性能（尤其是对于计算昂贵的变换）。</p>
    <p>因此，推荐的解决方法是在视图投影中的ol.layer.Tile上定义适当的可见范围。在<a
        href="https://openlayers.org/en/latest/examples/reprojection.html">重新投影示例</a>中演示了设置此类限制的方法。</p>
    <h3 id="resolution-calculation">分辨率计算</h3>
    <p>在确定要加载的源瓦片时，需要计算理想的源分辨率。
      <code>ol/reproj~calculateSourceResolution(sourceProj, targetProj, targetCenter, targetResolution)</code>
      函数计算理想的值，以在重新投影期间实现像素映射尽可能接近1：1，然后将其用于从源中选择适当的缩放级别。
    </p>
    <p>但是，通常不实用地为整个目标缩放级别使用相同的源缩放级别 -
      不同的投影在世界不同地区（例如EPSG：3857与EPSG：4326的极地地区）具有不同的分辨率，强制整个缩放级别的单一分辨率会导致一些瓦片被放大/缩小，可能需要加载大量的源瓦片。因此，分辨率映射是针对每个重新投影的瓦片单独计算的（在瓦片的范围中间）。
    </p>

  </div>

  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>